/**
 * 给软著注册收集代码
 * 
 * 提交登记软件源程序连续的前30页和连续的后30页（前、后各连续30页可以按开发时间排序，也可以按功能主次等自定义排序），每页不少于50行。若源程序整体不到60页，应提交全部源程序。
 */

import util from 'util';
import fs from 'fs';
import path from 'path';

const config = {
    dir: 'D:\\code-game\\utilize-the-south-wall\\assets\\Scripts',
    suffix: ['ts'], // 文件后缀
}


async function main() {
    const files = []
    await forEachFilesName(config.dir, (file) => {
        const suffix = file.split('.').pop()
        if (config.suffix.includes(suffix)) {
            files.push(file)
        }
    })

    let mdText = ''
    mdText += '```typescript\n'
    for (let file of files) {
        const content = await getFileContent(file)
        if (!content) {
            continue
        }

        mdText += `// ${file.replace(config.dir, '').replace(/\\/g, '/')} \n`
        mdText += `${content}\n`
    }
    mdText += '```\n'
    const saveFile = path.join(path.dirname(import.meta.url), 'collect-code-for-software.md').replace('file:\\', '')
    await hFs.saveFile(saveFile, mdText)
}

async function getFileContent(file) {
    const data = await hFs.readFile(file)
    const text = data?.toString() || ''
    let inComment = false
    return text.split('\n').filter(d => {
        const line = d?.trim()
        if (!line) {
            return false
        }

        // 好像注释不需要删除，因为也可以当做代码的一部分，用于证明代码是否抄袭
        // if (line.startsWith('/*')) {
        //     inComment = true
        // }
        // if (line.startsWith('//')) {
        //     return false
        // }
        // if (inComment) {
        //     if (line.endsWith('*/')) {
        //         inComment = false
        //     }
        //     return false
        // }

        return true
    }).join('\n')
}

async function forEachFilesName(dirPath, fn) {
    const files = await hFs.readdir(dirPath)
    if (!files) {
        console.error(`读取目录失败${dirPath}`)
        return
    }
    for (const file of files) {
        const filePath = path.join(dirPath, file)
        try {
            const stat = await getFileStat(filePath)
            if (stat.isDirectory()) {
                await forEachFilesName(filePath, fn)
            } else if (stat.isFile()) {
                fn(filePath)
            } else {
                console.error(`forEachFilesName的发现文件 ${filePath} 不存在：`)
            }
        } catch (err) {
            console.error(`forEachFilesName的遍历函数在处理${filePath}文件时报错：`, err)
        }
    }
}

async function getFileStat(path) {
    return new Promise((resolve, reject) => {
        fs.stat(path, (err, stats) => {
            if (err) {
                reject(err);
                return;
            }
            resolve(stats)
        })
    })
}

const hFs = {
    /**
     * 读取文件
     * */
    async readFile (filePath) {
      try {
        return await util.promisify(fs.readFile)(filePath)
      } catch (e) {
        return false
      }
    },
  
    // 读取目录
    async readdir (path, options) {
      try {
        return await util.promisify(fs.readdir)(path, options)
      } catch (e) {
        console.error(e)
        return false
      }
    },
  
    /**
     * 保存文件
     *
     * ps. 这个方法默认会覆盖文件全部内容
     *
     * @param filePath string 文件路径，要含文件名和扩展名，反正这个方法里不会自动给你加
     * @param fileData string | buffer 可以是字符串，也可以是buffer，是要保存的内容
     * @return boolean 保存成功还是失败
     * */
    saveFile (filePath, fileData) {
      return this.mkdir(
        filePath.split(path.sep).slice(0, -1).join(path.sep)
      ).then(function (succ) {
        if (!succ) { return false }
  
        return new Promise((resolve, reject) => {
          if (!(fileData instanceof Buffer)) {
            fileData = Buffer.from(fileData)
          }
  
          // 块方式写入文件
          const wstream = fs.createWriteStream(filePath)
  
          wstream.on('open', () => {
            const blockSize = 128
            const nbBlocks = Math.ceil(fileData.length / (blockSize))
            for (let i = 0; i < nbBlocks; i++) {
              const currentBlock = fileData.slice(
                blockSize * i,
                Math.min(blockSize * (i + 1), fileData.length)
              )
              wstream.write(currentBlock)
            }
  
            wstream.end()
          })
          wstream.on('error', (err) => {
            console.log('文件存储失败：', err)
            resolve(false)
          })
          wstream.on('finish', () => { resolve(true) })
        })
      })
    },
  
    /**
     * 创建多级目录，如果成功，或者目录早已存在，则返回true，否则返回false
     * @param dir string 需要创建的文件夹
     * @return boolean
     * */
    async mkdir (dir) {
      if (!dir) {
        return false
      }
      try {
        await util.promisify(fs.mkdir)(dir, {
          recursive: true
        })
        return true
      } catch (e) {
        let msg = '文件夹创建失败：'
        if (e.code === 'EEXIST') {
          return true
        } else if (e.code === 'ENOENT') { // 它的上级目录不存在，只有 recursive 不为true才会有这种情况
          msg = '上级目录不存在：'
        }
        console.log(msg, e.code, e.message)
      }
      return false
    }
  }

main().then(() => {
    console.log('成功')
}).catch((err) => {
    console.error('失败：', err)
})
